/**
 * 自动查询构建器实现
 * 提供链式API和装饰器支持
 * @author sun
 * @date 2024-03-30
 */

import {
  QueryOperator,
  DecoratorType,
  QueryResult,
  IConditionDef,
  IRangeDef,
  IGroupDef,
} from './types';

import { getQueryMetadata, hasQueryDecorators } from './decorators';

/**
 * 查询构建器类
 */
export class QueryBuilder {
  private conditions: any[] = [];
  private groupStack: Array<{
    operator: QueryOperator;
    conditions: any[];
  }> = [];

  /**
   * 添加等于条件
   * @param field 字段名
   * @param value 条件值
   */
  equal(field: string, value: any): QueryBuilder {
    if (this.isValidValue(value)) {
      this.addCondition([QueryOperator.EQUAL, field, value]);
    }
    return this;
  }

  /**
   * 添加不等于条件
   * @param field 字段名
   * @param value 条件值
   */
  notEqual(field: string, value: any): QueryBuilder {
    if (this.isValidValue(value)) {
      this.addCondition([QueryOperator.NOT_EQUAL, field, value]);
    }
    return this;
  }

  /**
   * 添加大于条件
   * @param field 字段名
   * @param value 条件值
   */
  greaterThan(field: string, value: any): QueryBuilder {
    if (this.isValidValue(value)) {
      this.addCondition([QueryOperator.GREATER_THAN, field, value]);
    }
    return this;
  }

  /**
   * 添加大于等于条件
   * @param field 字段名
   * @param value 条件值
   */
  greaterThanOrEqual(field: string, value: any): QueryBuilder {
    if (this.isValidValue(value)) {
      this.addCondition([QueryOperator.GREATER_THAN_OR_EQUAL, field, value]);
    }
    return this;
  }

  /**
   * 添加小于条件
   * @param field 字段名
   * @param value 条件值
   */
  lessThan(field: string, value: any): QueryBuilder {
    if (this.isValidValue(value)) {
      this.addCondition([QueryOperator.LESS_THAN, field, value]);
    }
    return this;
  }

  /**
   * 添加小于等于条件
   * @param field 字段名
   * @param value 条件值
   */
  lessThanOrEqual(field: string, value: any): QueryBuilder {
    if (this.isValidValue(value)) {
      this.addCondition([QueryOperator.LESS_THAN_OR_EQUAL, field, value]);
    }
    return this;
  }

  /**
   * 添加LIKE条件（添加%value%通配符实现包含匹配）
   * @param field 字段名
   * @param value 条件值
   */
  like(field: string, value: string): QueryBuilder {
    if (this.isValidValue(value)) {
      // 检查是否已经包含通配符
      if (value.startsWith('%') && value.endsWith('%')) {
        // 已经有前后通配符，保持原样
        this.addCondition([QueryOperator.LIKE, field, value]);
      } else {
        // 添加通配符
        this.addCondition([QueryOperator.LIKE, field, `%${value}%`]);
      }
    }
    return this;
  }

  /**
   * 添加开头匹配条件（添加value%通配符）
   * @param field 字段名
   * @param value 条件值
   */
  startsWith(field: string, value: string): QueryBuilder {
    if (this.isValidValue(value)) {
      this.addCondition([QueryOperator.LIKE, field, `${value}%`]);
    }
    return this;
  }

  /**
   * 添加结尾匹配条件（添加%value通配符）
   * @param field 字段名
   * @param value 条件值
   */
  endsWith(field: string, value: string): QueryBuilder {
    if (this.isValidValue(value)) {
      this.addCondition([QueryOperator.LIKE, field, `%${value}`]);
    }
    return this;
  }

  /**
   * 添加IN条件
   * @param field 字段名
   * @param values 条件值数组
   */
  in(field: string, values: any[]): QueryBuilder {
    if (Array.isArray(values) && values.length > 0) {
      this.addCondition([QueryOperator.IN, field, values]);
    }
    return this;
  }

  /**
   * 添加NOT IN条件
   * @param field 字段名
   * @param values 条件值数组
   */
  notIn(field: string, values: any[]): QueryBuilder {
    if (Array.isArray(values) && values.length > 0) {
      this.addCondition([QueryOperator.NOT_IN, field, values]);
    }
    return this;
  }

  /**
   * 添加BETWEEN条件
   * @param field 字段名
   * @param start 开始值
   * @param end 结束值
   */
  between(field: string, start: any, end: any): QueryBuilder {
    if (this.isValidValue(start) && this.isValidValue(end)) {
      this.addCondition([QueryOperator.BETWEEN, field, [start, end]]);
    }
    return this;
  }

  /**
   * 添加范围条件
   * @param field 字段名
   * @param range 范围数组 [min, max]
   * @param minOperator 最小值操作符
   * @param maxOperator 最大值操作符
   */
  range(
    field: string,
    range: [any, any],
    minOperator = QueryOperator.GREATER_THAN_OR_EQUAL,
    maxOperator = QueryOperator.LESS_THAN_OR_EQUAL,
  ): QueryBuilder {
    if (Array.isArray(range) && range.length === 2) {
      const [min, max] = range;
      if (this.isValidValue(min)) {
        this.addCondition([minOperator, field, min]);
      }
      if (this.isValidValue(max)) {
        this.addCondition([maxOperator, field, max]);
      }
    }
    return this;
  }

  /**
   * 开始AND条件组
   */
  beginAndGroup(): QueryBuilder {
    this.groupStack.push({
      operator: QueryOperator.AND,
      conditions: [],
    });
    return this;
  }

  /**
   * 开始OR条件组
   */
  beginOrGroup(): QueryBuilder {
    this.groupStack.push({
      operator: QueryOperator.OR,
      conditions: [],
    });
    return this;
  }

  /**
   * 结束当前条件组
   */
  endGroup(): QueryBuilder {
    if (this.groupStack.length > 0) {
      const group = this.groupStack.pop()!;
      const conditions = group.conditions;

      if (conditions.length > 0) {
        const groupCondition = [group.operator, ...conditions];

        if (this.groupStack.length > 0) {
          // 添加到父组
          this.groupStack[this.groupStack.length - 1].conditions.push(groupCondition);
        } else {
          // 添加到顶级条件
          this.conditions.push(groupCondition);
        }
      }
    }
    return this;
  }

  /**
   * 从对象构建查询条件
   * 支持MongoDB风格的对象表达式
   */
  fromObject(obj: Record<string, any>): QueryBuilder {
    if (!obj) return this;

    const processObject = (obj: Record<string, any>): any[] | null => {
      const conditions: any[] = [];

      // 处理特殊操作符
      if (obj.$and) {
        const andConditions = Array.isArray(obj.$and)
          ? obj.$and.map((cond) => processObject(cond)).filter(Boolean)
          : [];
        if (andConditions.length > 0) {
          conditions.push([QueryOperator.AND, ...andConditions]);
        }
      }

      if (obj.$or) {
        const orConditions = Array.isArray(obj.$or)
          ? obj.$or.map((cond) => processObject(cond)).filter(Boolean)
          : [];
        if (orConditions.length > 0) {
          conditions.push([QueryOperator.OR, ...orConditions]);
        }
      }

      // 处理普通字段
      for (const key in obj) {
        if (key === '$and' || key === '$or') continue;

        const value = obj[key];

        if (!this.isValidValue(value)) continue;

        if (typeof value === 'object' && !Array.isArray(value)) {
          // 处理字段查询操作符
          for (const op in value) {
            const opValue = value[op];
            if (!this.isValidValue(opValue)) continue;

            switch (op) {
              case '$eq':
                conditions.push([QueryOperator.EQUAL, key, opValue]);
                break;
              case '$ne':
                conditions.push([QueryOperator.NOT_EQUAL, key, opValue]);
                break;
              case '$gt':
                conditions.push([QueryOperator.GREATER_THAN, key, opValue]);
                break;
              case '$gte':
                conditions.push([QueryOperator.GREATER_THAN_OR_EQUAL, key, opValue]);
                break;
              case '$lt':
                conditions.push([QueryOperator.LESS_THAN, key, opValue]);
                break;
              case '$lte':
                conditions.push([QueryOperator.LESS_THAN_OR_EQUAL, key, opValue]);
                break;
              case '$like':
                // 检查是否已经包含通配符
                if (
                  typeof opValue === 'string' &&
                  opValue.startsWith('%') &&
                  opValue.endsWith('%')
                ) {
                  // 已经有前后通配符，保持原样
                  conditions.push([QueryOperator.LIKE, key, opValue]);
                } else {
                  // 添加通配符
                  conditions.push([QueryOperator.LIKE, key, `%${opValue}%`]);
                }
                break;
              case '$startsWith':
                if (typeof opValue === 'string') {
                  conditions.push([QueryOperator.LIKE, key, `${opValue}%`]);
                }
                break;
              case '$endsWith':
                if (typeof opValue === 'string') {
                  conditions.push([QueryOperator.LIKE, key, `%${opValue}`]);
                }
                break;
              case '$in':
                if (Array.isArray(opValue) && opValue.length > 0) {
                  conditions.push([QueryOperator.IN, key, opValue]);
                }
                break;
              case '$nin':
                if (Array.isArray(opValue) && opValue.length > 0) {
                  conditions.push([QueryOperator.NOT_IN, key, opValue]);
                }
                break;
              case '$between':
                if (
                  Array.isArray(opValue) &&
                  opValue.length === 2 &&
                  this.isValidValue(opValue[0]) &&
                  this.isValidValue(opValue[1])
                ) {
                  conditions.push([QueryOperator.BETWEEN, key, opValue]);
                }
                break;
            }
          }
        } else {
          // 简单等于条件
          conditions.push([QueryOperator.EQUAL, key, value]);
        }
      }

      return conditions.length > 0 ? conditions : null;
    };

    const conditions = processObject(obj);
    if (conditions) {
      for (const condition of conditions) {
        this.addCondition(condition);
      }
    }

    return this;
  }

  /**
   * 从装饰器构建查询条件
   * @param obj 目标对象实例
   */
  fromDecorators(obj: any): QueryBuilder {
    if (!hasQueryDecorators(obj)) {
      return this;
    }

    const conditions = getQueryMetadata(obj);
    if (!conditions) {
      return this;
    }

    Object.entries(conditions).forEach(([key, conditionDef]: [string, any]) => {
      // 获取属性值
      const value = obj[key];

      // 如果值为null或undefined，则跳过此条件
      if (!this.isValidValue(value)) {
        return;
      }

      switch (conditionDef.type) {
        case DecoratorType.CONDITION:
          // 处理普通条件
          if (conditionDef.operator === QueryOperator.BETWEEN && Array.isArray(value)) {
            if (value.length < 2 || !this.isValidValue(value[0]) || !this.isValidValue(value[1])) {
              return;
            }
          }

          // 特殊处理 LIKE 操作符，添加 %% 通配符
          if (conditionDef.operator === QueryOperator.LIKE && typeof value === 'string') {
            // 避免重复添加通配符
            if (value.startsWith('%') && value.endsWith('%')) {
              // 已经有前后通配符，保持原样
              this.addCondition([conditionDef.operator, conditionDef.field, value]);
            } else {
              // 添加通配符
              this.addCondition([conditionDef.operator, conditionDef.field, `%${value}%`]);
            }
          } else {
            // 其他操作符直接使用原值
            this.addCondition([conditionDef.operator, conditionDef.field, value]);
          }
          break;

        case DecoratorType.RANGE:
          // 处理范围条件
          if (Array.isArray(value) && value.length === 2) {
            const [min, max] = value;
            if (this.isValidValue(min)) {
              this.addCondition([conditionDef.minOperator, conditionDef.field, min]);
            }
            if (this.isValidValue(max)) {
              this.addCondition([conditionDef.maxOperator, conditionDef.field, max]);
            }
          }
          break;

        case DecoratorType.AND_GROUP:
        case DecoratorType.OR_GROUP:
          // 处理嵌套条件组
          if (Array.isArray(value) && value.length > 0) {
            const validItems = value.filter(
              (item) => item && (Array.isArray(item) || typeof item === 'object'),
            );

            if (validItems.length > 0) {
              // 构建嵌套条件
              const nestedConditions = validItems
                .map((item) => {
                  // 如果项是一个使用了装饰器的对象
                  if (hasQueryDecorators(item)) {
                    const nestedBuilder = new QueryBuilder();
                    nestedBuilder.fromDecorators(item);
                    const nestedResult = nestedBuilder.build();
                    return nestedResult.length > 0 ? nestedResult : null;
                  }
                  // 如果是数组，假定已经是格式化的条件
                  return item;
                })
                .filter(Boolean);

              if (nestedConditions.length > 0) {
                const operator =
                  conditionDef.type === DecoratorType.AND_GROUP
                    ? QueryOperator.AND
                    : QueryOperator.OR;
                this.addCondition([operator, ...nestedConditions]);
              }
            }
          }
          break;

        default:
          // 未知的装饰器类型，跳过
          break;
      }
    });

    return this;
  }

  /**
   * 添加自定义条件数组
   * @param condition 条件数组
   */
  addRaw(condition: any[]): QueryBuilder {
    if (Array.isArray(condition) && condition.length > 0) {
      this.addCondition(condition);
    }
    return this;
  }

  /**
   * 重置查询构建器
   */
  reset(): QueryBuilder {
    this.conditions = [];
    this.groupStack = [];
    return this;
  }

  /**
   * 构建查询条件
   * @returns 查询条件数组
   */
  build(): any[] {
    // 确保所有组都已关闭
    while (this.groupStack.length > 0) {
      this.endGroup();
    }

    if (this.conditions.length === 0) {
      return [];
    }
    if (this.conditions.length === 1) {
      return this.conditions[0];
    }
    return [QueryOperator.AND, ...this.conditions];
  }

  /**
   * 检查值是否有效（非空）
   * @param value 要检查的值
   */
  private isValidValue(value: any): boolean {
    // 空字符串、null、undefined视为无效值
    if (value === undefined || value === null || value === '') {
      return false;
    }

    // 空数组视为无效值
    if (Array.isArray(value) && value.length === 0) {
      return false;
    }

    // 其他值视为有效
    return true;
  }

  /**
   * 添加条件
   * @param condition 查询条件
   */
  private addCondition(condition: any) {
    if (this.groupStack.length > 0) {
      // 添加到当前组
      this.groupStack[this.groupStack.length - 1].conditions.push(condition);
    } else {
      // 添加到顶级条件
      this.conditions.push(condition);
    }
    return this;
  }

  /**
   * 创建一个新的查询构建器实例
   */
  static create(): QueryBuilder {
    return new QueryBuilder();
  }

  /**
   * 从对象创建查询条件
   * @param obj 查询对象
   */
  static fromObject(obj: Record<string, any>): any[] {
    return new QueryBuilder().fromObject(obj).build();
  }

  /**
   * 从装饰器构建查询条件
   * @param obj 目标对象实例
   */
  static fromDecorators(obj: any): any[] {
    return new QueryBuilder().fromDecorators(obj).build();
  }
}
